/* *
 * @file    audio_tts.c
 * @author  Azolla (1228449928@qq.com)
 * @brief   TTS I2S audio code.
 * @version 0.1
 * @date    2024-02-19
 * 
 * @copyright Copyright (c) 2024
 * */
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_system.h"
#include "esp_check.h"

#include "esp_tts.h"
#include "esp_tts_voice_xiaole.h"
#include "esp_tts_voice_template.h"
#include "esp_tts_player.h"
  
#include "wav_encoder.h"
#include "wav_decoder.h"
#include "esp_partition.h"
#include "esp_idf_version.h"

#include "audio_i2s.h"
#include "audio_tts.h"

#define TAG  "audio_tts"

#ifdef TAG
#define TTS_LOGI(format, ...)    ESP_LOGI(TAG, format, ##__VA_ARGS__)
#define TTS_LOGW(format, ...)    ESP_LOGW(TAG, format, ##__VA_ARGS__)
#define TTS_LOGE(format, ...)    ESP_LOGE(TAG, format, ##__VA_ARGS__)
#else
#define TTS_LOGI(format, ...)
#define TTS_LOGW(format, ...)
#define TTS_LOGE(format, ...)
#endif

static QueueHandle_t xQueue = NULL;

int audio_tts_player(const char *text)
{
    audio_tts_stream_t stream = { 0 };
    stream.text = (char *)text;
    return xQueueSend(xQueue, &stream, (TickType_t)0);   
}

void audio_tts_task(void *arg)
{
    esp_tts_handle_t *tts_handle = (esp_tts_handle_t *)arg;
    audio_tts_stream_t stream = { 0 };
    bool tts_parse = false;
    int pcm_len = 0;
    // stream.text = heap_caps_malloc(256, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
    while ( true ) { // sample rate:16000Hz, int16, mono
        if (xQueueReceive(xQueue, &stream, 0) == pdTRUE) {  // 又有新TTS需要播放，打断播放新的！
            if (stream.text == NULL || strlen(stream.text) < 2) continue;
            esp_tts_stream_reset(tts_handle); // reset tts stream and clean all cache of TTS instance.
            tts_parse = esp_tts_parse_chinese(tts_handle, stream.text);
        }

        if (tts_parse) {
            short *pcm_data = esp_tts_stream_play(tts_handle, &pcm_len, 4);  // speed = 4
            if (pcm_len <= 0) { // over | fail. 
                tts_parse = false;
                continue;
            }
            audio_i2s_write(pcm_data, pcm_len * 2);
        } else {
            vTaskDelay(100);  // feed wdt.
        }
    }
}

// TTS 输出格式为：单声道，16 bit @ 16000Hz。 
void audio_tts_init(void)
{
    esp_log_level_set("tts_parser", ESP_LOG_WARN);
    
    // initial voice set from separate voice data partition
    const esp_partition_t *part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "tts");
    if (part == NULL) {
        TTS_LOGI("Couldn't find voice data partition!\n");
        return;
    } else {
        TTS_LOGI("voice_data paration size:%ld\n", part->size);
    }
    void *tts_voice;
    esp_partition_mmap_handle_t mmap;
    esp_err_t err = esp_partition_mmap(part, 0, part->size, ESP_PARTITION_MMAP_DATA, (const void **)&tts_voice, &mmap);
    if (err != ESP_OK) {
        TTS_LOGI("Couldn't map voice data partition!\n");
        return;
    }
    esp_tts_voice_t *voice = esp_tts_voice_set_init(&esp_tts_voice_template, tts_voice);
    esp_tts_handle_t *tts_handle = esp_tts_create(voice);

    xQueue = xQueueCreate(1, sizeof(audio_tts_stream_t));
    xTaskCreatePinnedToCore(audio_tts_task, "audio_tts", 5 * 1024, tts_handle, 4, NULL, PRO_CPU_NUM); 
}

// source flash_voicedata.sh managed_components/espressif__esp-sr/esp-tts/esp_tts_chinese/esp_tts_voice_data_xiaole.dat  /dev/ttyACM0
// source flash_voicedata.sh managed_components/espressif__esp-sr/esp-tts/esp_tts_chinese/esp_tts_voice_data_xiaoxin_small.dat  /dev/ttyACM0
